/*
* coder: Dzlua
* email: 505544956@qq.com
* time : 2018-04-17 13:41
*/
#pragma once
#ifndef __CONVERT_HPP__
#define __CONVERT_HPP__

#include <string>
#include <sstream>
#include <codecvt>
#include <locale>

namespace {

// for format.
template <typename T, typename D>
auto _format(T& ss, const D& d) {
    ss << d;
}
    
}

UI_BEGIN_NAMESPACE

/*
* for strings.
*/
typedef std::string string;
typedef std::wstring wstring;
#if defined(_UNICODE) || defined(UNICODE)
    typedef wstring tstring;
#else
    typedef string tstring;
#endif

/*
* code convert
*/
// convert wstring to string.
string w2s(const wstring& s) {
    string dst;
    std::locale sys_locale("");

    const wchar_t* data_from = s.c_str();
    const wchar_t* data_from_end = s.c_str() + s.size();
    const wchar_t* data_from_next = 0;

    int wchar_size = 4;
    char* data_to = new char[(s.size() + 1) * wchar_size];
    char* data_to_end = data_to + (s.size() + 1) * wchar_size;
    char* data_to_next = 0;

    memset(data_to, 0, (s.size() + 1) * wchar_size);
    typedef std::codecvt<wchar_t, char, mbstate_t> convert_face;
    mbstate_t out_state = { 0 };

    auto result = std::use_facet<convert_face>(sys_locale).out(
        out_state,
        data_from, data_from_end, data_from_next,
        data_to, data_to_end, data_to_next );
    if (result == convert_face::ok) dst = data_to;
    delete[] data_to;
    return std::move(dst);
}
// convert string to wstring.
wstring s2w(const string& s) {
    wstring dst;
    std::locale sys_locale("");

    const char* data_from = s.c_str();
    const char* data_from_end = s.c_str() + s.size();
    const char* data_from_next = 0;

    wchar_t* data_to = new wchar_t[s.size() + 1];
    wchar_t* data_to_end = data_to + s.size() + 1;
    wchar_t* data_to_next = 0;

    wmemset(data_to, 0, s.size() + 1);
    typedef std::codecvt<wchar_t, char, mbstate_t> convert_face;
    mbstate_t in_state = { 0 };

    auto result = std::use_facet<convert_face>(sys_locale).in(
        in_state,
        data_from, data_from_end, data_from_next,
        data_to, data_to_end, data_to_next );
    if (result == convert_face::ok) dst = data_to;
    delete[] data_to;
    return std::move(dst);
}
// convert utf-8 string to wstring.
wstring u2w(const string& u8str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    return conv.from_bytes(u8str);
}
// convert wstring to utf-8 string.
string w2u(const wstring& s) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    return conv.to_bytes(s);
}
// convert utf-8 to string.
string u2s(const string& s) {
    return w2s(u2w(s));
}
// convert string to utf-8.
string s2u(const string& s) {
    return w2u(s2w(s));
}

// convert string to tstring.
tstring s2t(const string& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return s2w(s);
    #else
        return s;
    #endif
}
// convert wstring to tstring.
tstring w2t(const wstring& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return s;
    #else
        return w2s(s);
    #endif
}
// convert utf-8 to tstring.
tstring u2t(const string& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return u2w(s);
    #else
        return u2s(s);
    #endif
}
// convert tstring to string.
string t2s(const tstring& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return w2s(s);
    #else
        return s;
    #endif
}
// convert tstring to wstring.
wstring t2w(const tstring& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return s;
    #else
        return s2w(s);
    #endif
}
// convert tstring to utf-8.
string t2u(const tstring& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return w2u(s);
    #else
        return s2u(s);
    #endif
}

/*
* anything translate to string.
*/
template <typename T>
string any2str(const T& d) {
    std::stringstream ss;
    ss << d;
    return ss.str();
}
template <>
string any2str(const string& d) {
    return d;
}
template <>
string any2str(const wstring& d) {
    return w2s(d);
}

template <typename T>
wstring any2wstr(const T& d) {
    std::wstringstream ss;
    ss << d;
    return ss.str();
}
template <>
wstring any2wstr(const string& d) {
    return s2w(d);
}
template <>
wstring any2wstr(const wstring& d) {
    return d;
}

template <typename T>
auto any2tstr(const T& d) {
    #if defined(_UNICODE) || defined(UNICODE)
        return any2wstr<T>(d);
    #else
        return any2str<T>(d);
    #endif
}

/*
* string translate to anything.
*/
template <typename T>
T str2any(const string& s) {
    T d;
    std::stringstream ss(s);
    ss >> d;
    return d;
}
template <>
string str2any(const string& s) {
    return s;
}
template <>
wstring str2any(const string& s) {
    return s2w(s);
}

template <typename T>
T wstr2any(const wstring& s) {
    T d;
    std::wstringstream ss(s);
    ss >> d;
    return d;
}
template <>
string wstr2any(const wstring& s) {
    return w2s(s);
}
template <>
wstring wstr2any(const wstring& s) {
    return s;
}
template <>
char wstr2any(const wstring& s) {
    return str2any<short>(w2s(s));
}
template <>
unsigned char wstr2any(const wstring& s) {
    return str2any<unsigned short>(w2s(s));
}

template <typename T>
auto tstr2any(const tstring& s) {
    #if defined(_UNICODE) || defined(UNICODE)
        return wstr2any<T>(s);
    #else
        return str2any<T>(s);
    #endif
}

/*
* format string
*/
template <typename... Args>
string format(Args&&... args) {
    std::stringstream ss;
    std::initializer_list<int>{ (
        _format(ss, std::forward<Args>(args))
        , 0 )...};
    return ss.str();
}
template <typename... Args>
wstring wformat(Args&&... args) {
    std::wstringstream ss;
    std::initializer_list<int>{ (
        _format(ss, std::forward<Args>(args))
        , 0 )...};
    return ss.str();
}
template <typename... Args>
tstring tformat(Args&&... args) {
    #if defined(_UNICODE) || defined(UNICODE)
        return wformat(args...);
    #else
        return format(args...);
    #endif
}

UI_END_NAMESPACE

#endif
